namespace ColumnOrderingSetup
{
    using System;
    using System.Collections.Generic;

    using Microsoft.SharePoint;

    public class DepartmentInformationBL
    {
        #region Fields

        const string DEPARTMENTADMINISTRATIONLIST = "Department Administration List";
        const string DEPARTMENTLISTNAME = "Department List Name";
        const string STOREREFERENCEID = "Store Reference ID";
        const string TITLE = "Title";

        #endregion Fields

        #region Properties

        List<DepartmentOrderingLookup> departmentOrderingLookup
        {
            get;
            set;
        }

        #endregion Properties

        #region Methods

        internal Exception CleanDeletedFields(string siteURL)
        {
            Exception error = null;

            try
            {
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        DepartmentVisibleFields deptFields = new DepartmentVisibleFields();

                        SPList orderingList = storeWeb.Lists["Department Ordering Lookup"];
                        SPList currentVerificationList;
                        List<DepartmentOrderingLookup> allItems = new List<DepartmentOrderingLookup>();
                        //load all items
                        foreach (SPListItem item in orderingList.Items)
                        {
                            DepartmentOrderingLookup newItem = new DepartmentOrderingLookup();
                            newItem.SourceInformationList = item["Source Information List"].ToString();
                            newItem.FieldName = item["Field Name"].ToString();
                            newItem.ID = item.ID;
                            allItems.Add(newItem);
                        }
                        //loop through all items
                        foreach (DepartmentOrderingLookup lookup in allItems)
                        {
                            //get the list
                            currentVerificationList = storeWeb.Lists[lookup.SourceInformationList];
                            //ensure field
                            if (!currentVerificationList.Fields.ContainsField(lookup.FieldName))
                            {
                                //delete this item
                                SPSecurity.RunWithElevatedPrivileges(delegate()
                                {
                                    orderingList.Items.DeleteItemById(lookup.ID);
                                });
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            return error;
        }

        internal Exception CleanDepartmentOrdering(string siteURL)
        {
            Exception error = null;

            try
            {
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        SPList departmentListValues = storeWeb.Lists["Department Administration List"];
                        SPList orderingList = storeWeb.Lists["Department Ordering Lookup"];
                        SPQuery getFields = new SPQuery();
                        string currentDepartment = "";
                        SPListItemCollection orderedFields;
                        int i = 1;

                        foreach (SPListItem item in departmentListValues.Items)
                        {
                            currentDepartment = item["Department Name"].ToString();
                            getFields = new SPQuery();
                            getFields.Query = "<Where><Eq><FieldRef Name='Department_x0020_Owner' /><Value Type='Text'>" + currentDepartment + "</Value></Eq></Where><OrderBy><FieldRef Name='Department_x0020_Owner' Ascending='True' /><FieldRef Name='Order_x0020_Number' Ascending='True' /></OrderBy>";
                            orderedFields = orderingList.GetItems(getFields);
                            i = 1;
                            if (orderedFields.Count > 0)
                            {
                                foreach (SPListItem itemFields in orderedFields)
                                {
                                    itemFields["Order Number"] = i;
                                    if (itemFields["ReadOnly"] == null)
                                        itemFields["ReadOnly"] = true;
                                    itemFields.Update();
                                    i++;
                                }
                            }
                        }
                        orderingList.Update();
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            return error;
        }

        internal Exception CleanUpColumnWidth(string siteURL)
        {
            Exception error = null;

            try
            {
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        SPList orderingList = storeWeb.Lists["Department Ordering Lookup"];

                        foreach (SPListItem item in orderingList.Items)
                        {

                            if (item["Column Width"] == null)
                            {
                                if (item["Field Name"].ToString().Equals("Comments"))
                                    item["Column Width"] = 250;
                                else
                                    item["Column Width"] = 125;
                            }
                            else
                            {
                                if (item["Column Width"].ToString() == "0")
                                {
                                    if (item["Field Name"].ToString().Equals("Comments"))
                                        item["Column Width"] = 250;
                                    else
                                        item["Column Width"] = 125;
                                }
                            }

                            item.Update();

                        }
                        orderingList.Update();
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            return error;
        }

        internal Exception GetAllInternalFields(string siteURL)
        {
            Exception error = null;

            try
            {
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        string currentField = "";
                        string currentInternalName = "";
                        string currentFieldType = "";

                        storeWeb.AllowUnsafeUpdates = true;
                        SPList departmentListValues = storeWeb.Lists["Department Ordering Lookup"];
                        SPList currentDepartmentList = null;
                        SPQuery singleDepartmentDepartments = new SPQuery();

                        foreach (SPListItem item in departmentListValues.Items)
                        {
                            currentField = item["Field Name"].ToString();
                            currentDepartmentList = storeWeb.Lists[item["Source Department"].ToString()];
                            currentInternalName = currentDepartmentList.Fields[item["Field Name"].ToString()].InternalName;
                            currentFieldType = currentDepartmentList.Fields[item["Field Name"].ToString()].TypeAsString;
                            item["Internal Field Name"] = currentInternalName;
                            item["FieldType"] = currentFieldType;
                            item.Update();
                        }

                        departmentListValues.Update();
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            return error;
        }

        internal Exception LoadAllDepartmentsFields(string siteURL)
        {
            const string DEPARTMENTORDERINGLOOKUP = "Department Ordering Lookup";
            const string DEPARTMENTNAMECOLUMN = "Department Name";
            const string VERSION = "Version";
            const string CREATED = "Created";
            const string CREATEDBY = "Created By";
            const string CONTENTTYPE = "Content Type";
            const string DEPARTMENTNAME = "Department Name";
            const string SOURCEINFORMATIONLIST = "Source Information List";
            const string ORDERNUMBER = "Order Number";
            const string FIELDNAME = "Field Name";
            const string SOURCEDEPARTMENT = "Source Department";
            const string DEPARTMENTOWNER = "Department Owner";
            const string READONLY = "ReadOnly";

            Exception error = null;

            try
            {
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        SPList departmentAdministrationList = storeWeb.Lists[DEPARTMENTADMINISTRATIONLIST];
                        SPList departmentOrderingLookup = storeWeb.Lists[DEPARTMENTORDERINGLOOKUP];

                        int orderNumber = 0;
                        foreach (SPListItem item in departmentAdministrationList.Items)
                        {
                            //get the department list
                            SPList departmentList = storeWeb.Lists[item[DEPARTMENTLISTNAME].ToString()];
                            //get the next order number for the column
                            orderNumber = GetMaxOrderingNumber(siteURL, item[DEPARTMENTNAMECOLUMN].ToString());
                            //loop through all fields in the department list
                            foreach (SPField departmentField in departmentList.Fields)
                            {
                                //ensure field is NOT HIDDEN and IS USERCREATABLE
                                if (departmentField.FieldTypeDefinition.UserCreatable && !departmentField.Hidden)
                                {
                                    if (!departmentField.Title.Trim().Equals(VERSION) &&
                                        !departmentField.Title.Trim().Equals(CREATED) &&
                                        !departmentField.Title.Trim().Equals(CREATEDBY) &&
                                        !departmentField.Title.Trim().Equals(CONTENTTYPE) &&
                                        !departmentField.Title.Trim().Equals(STOREREFERENCEID))
                                    {
                                        //ensure field
                                        if (!DoesFieldExistingOrderList(siteURL, item[DEPARTMENTNAMECOLUMN].ToString(),
                                            departmentField.Title.ToString(), item[DEPARTMENTNAMECOLUMN].ToString()))
                                        {
                                            SPListItem newFieldItem = departmentOrderingLookup.Items.Add();
                                            newFieldItem[TITLE] = departmentField.Title.ToString();
                                            newFieldItem[SOURCEINFORMATIONLIST] = item[DEPARTMENTLISTNAME].ToString();

                                            newFieldItem[ORDERNUMBER] = orderNumber;
                                            newFieldItem[FIELDNAME] = departmentField.Title.ToString();
                                            newFieldItem[SOURCEDEPARTMENT] = item[DEPARTMENTNAME].ToString();
                                            newFieldItem[DEPARTMENTOWNER] = item[DEPARTMENTNAME].ToString();
                                            newFieldItem[READONLY] = true;
                                            newFieldItem.Update();
                                            departmentOrderingLookup.Update();
                                            orderNumber++;
                                        }
                                    }
                                }
                            }

                        }
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            return error;
        }

        internal Exception ValidateAllDepartmentData(string siteURL)
        {
            const string REFERENCE = "Reference #";
            const string STORESDETAIL = "Stores Detail";

            Exception error = null;
            try
            {
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        storeWeb.AllowUnsafeUpdates = true;

                        // cache store information
                        List<StoreInfo> storeInfo = new List<StoreInfo>();
                        SPList storesDetail = storeWeb.Lists[STORESDETAIL];
                        foreach (SPItem item in storesDetail.Items)
                        {
                            StoreInfo o = new StoreInfo();
                            o.RefId = int.Parse(item[REFERENCE].ToString());
                            o.Title = item[TITLE].ToString();
                            storeInfo.Add(o);
                        }
                        storeInfo.Sort((a, b) => a.RefId.CompareTo(b.RefId)); // sort store information by reference identifier

                        // for every item in the departmental store list
                        SPList departmentAdministrationList = storeWeb.Lists[DEPARTMENTADMINISTRATIONLIST];
                        foreach (SPListItem item in departmentAdministrationList.Items)
                        {
                            SPList departmentList = storeWeb.Lists[item[DEPARTMENTLISTNAME].ToString()];
                            // if necessary add store reference identifier column to list
                            SPSecurity.RunWithElevatedPrivileges(delegate()
                            {
                                if (!departmentList.Fields.ContainsField(STOREREFERENCEID))
                                {
                                    departmentList.Fields.Add(STOREREFERENCEID, SPFieldType.Number, false);
                                    departmentList.Update();
                                }
                            });

                            // read every item from list and collect store reference identifiers
                            List<int> storesAssocWithDepartment = new List<int>();
                            foreach (SPListItem itm in departmentList.Items)
                                storesAssocWithDepartment.Add(int.Parse(itm[STOREREFERENCEID].ToString()));

                            // determine missing stores
                            List<StoreInfo> missingStores = new List<StoreInfo>();
                            foreach (StoreInfo si in storeInfo)
                                if (!storesAssocWithDepartment.Exists(a => a.CompareTo(si.RefId) == 0))
                                    missingStores.Add(si);

                            // add the missing stores
                            foreach (StoreInfo o in missingStores)
                            {
                                SPListItem p = departmentList.Items.Add();
                                p[STOREREFERENCEID] = o.RefId;
                                p[TITLE] = o.Title;
                                p.Update();
                                departmentList.Update();
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                error = e;
            }

            return error;
        }

        void DeleteSelectedOrderField(string siteURL, string sourceDepartment, string targetDepartment, string fieldName)
        {
            using (SPSite storeSite = new SPSite(siteURL))
            {
                using (SPWeb storeWeb = storeSite.OpenWeb())
                {
                    DepartmentVisibleFields deptFields = new DepartmentVisibleFields();
                    SPSecurity.RunWithElevatedPrivileges(delegate()
                    {
                        SPList orderingList = storeWeb.Lists["Department Ordering Lookup"];
                        SPQuery validateField = new SPQuery();
                        validateField.Query = "<Where><And><Eq><FieldRef Name='Field_x0020_Name' /><Value Type='Text'>" + fieldName + "</Value></Eq><And><Eq><FieldRef Name='Source_x0020_Department' /><Value Type='Text'>" + targetDepartment + "</Value></Eq><Eq><FieldRef Name='Department_x0020_Owner' /><Value Type='Text'>" + sourceDepartment + "</Value></Eq></And></And></Where>";
                        SPListItemCollection selectedFields = orderingList.GetItems(validateField);
                        if (selectedFields.Count == 0)
                            return;
                        else
                        {
                            selectedFields[0].Delete();

                        }
                    });
                }
            }
        }

        bool DoesFieldExistingOrderList(string siteURL, string sourceDepartment, string fieldName, string targetDepartment)
        {
            if (departmentOrderingLookup == null)
                loadDepartmentOrderingLookup(siteURL);

            //bool result = true;
            using (SPSite storeSite = new SPSite(siteURL))
            {
                using (SPWeb storeWeb = storeSite.OpenWeb())
                {
                    //check the list for matching items
                    foreach (DepartmentOrderingLookup item in departmentOrderingLookup)
                    {
                        if (item.FieldName == fieldName && item.SourceDept == sourceDepartment && item.DepartmentOwner == targetDepartment)
                        {
                            //item found
                            return true;
                        }
                    }
                    //if we get out of the loop, none found
                    return false;
                }
            }
        }

        int GetMaxOrderingNumber(string siteURL, string ownerDepartment)
        {
            int result = 1;
            using (SPSite storeSite = new SPSite(siteURL))
            {
                using (SPWeb storeWeb = storeSite.OpenWeb())
                {
                    //create list to hold lookups from list
                    List<DepartmentOrderingLookup> orderingListItems = new List<DepartmentOrderingLookup>();
                    //get list
                    SPList orderingList = storeWeb.Lists["Department Ordering Lookup"];
                    //load list
                    foreach (SPListItem item in orderingList.Items)
                    {
                        if (item["Department_x0020_Owner"].ToString() == ownerDepartment)
                        {
                            //create item
                            DepartmentOrderingLookup newItem = new DepartmentOrderingLookup();
                            newItem.DepartmentOwner = ownerDepartment;
                            //newItem.ID = item["ID"];
                            newItem.OrderNumber = int.Parse(item["Order_x0020_Number"].ToString());
                            //check the resulting order number
                            if (result < newItem.OrderNumber)
                            {
                                result = newItem.OrderNumber;
                            }
                            //add item
                            orderingListItems.Add(newItem);
                            //reset
                            newItem = null;
                        }
                    }
                    //find the max number
                    if (orderingListItems.Count < 1)
                    {
                        //return 1
                        return 1;
                    }
                    else
                    {
                        result = result++;
                    }
                }
            }
            return result;
        }

        void loadDepartmentOrderingLookup(string siteURL)
        {
            if (departmentOrderingLookup == null)
            {
                departmentOrderingLookup = new List<DepartmentOrderingLookup>();
                using (SPSite storeSite = new SPSite(siteURL))
                {
                    using (SPWeb storeWeb = storeSite.OpenWeb())
                    {
                        SPList orderingList = storeWeb.Lists["Department Ordering Lookup"];
                        foreach (SPListItem item in orderingList.Items)
                        {
                            DepartmentOrderingLookup o = new DepartmentOrderingLookup();
                            o.SourceDept = item["Source_x0020_Department"].ToString();
                            o.DepartmentOwner = item["Department_x0020_Owner"].ToString();
                            o.FieldName = item["Field_x0020_Name"].ToString();
                            departmentOrderingLookup.Add(o);
                        }
                    }
                }
            }
        }

        #endregion Methods

        #region Nested Types

        class DepartmentOrderingLookup
        {
            #region Properties

            public string DepartmentOwner
            {
                get;
                set;
            }

            public string FieldName
            {
                get;
                set;
            }

            public int ID
            {
                get;
                set;
            }

            public int OrderNumber
            {
                get;
                set;
            }

            public string SourceDept
            {
                get;
                set;
            }

            public string SourceInformationList
            {
                get;
                set;
            }

            #endregion Properties
        }

        class StoreInfo
        {
            #region Properties

            public int RefId
            {
                get;
                set;
            }

            public string Title
            {
                get;
                set;
            }

            #endregion Properties
        }

        #endregion Nested Types
    }
}